/**********
This library is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the
Free Software Foundation; either version 3 of the License, or (at your
option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.)

This library is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
more details.

You should have received a copy of the GNU Lesser General Public License
along with this library; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
**********/
// "liveMedia"
// Copyright (c) 1996-2018 Live Networks, Inc.  All rights reserved.
// Author Bernhard Feiten
// A filter that breaks up an H.263plus video stream into frames.
//

#include "include/H263plusVideoStreamFramer.hh"
#include "H263plusVideoStreamParser.hh"

#include <string.h>
#include "../groupsock/include/GroupsockHelper.hh"


///////////////////////////////////////////////////////////////////////////////
////////// H263plusVideoStreamFramer implementation //////////
//public///////////////////////////////////////////////////////////////////////
H263plusVideoStreamFramer *H263plusVideoStreamFramer::createNew(
        UsageEnvironment &env,
        FramedSource *inputSource) {
    // Need to add source type checking here???  #####
    H263plusVideoStreamFramer *fr;
    fr = new H263plusVideoStreamFramer(env, inputSource);
    return fr;
}


///////////////////////////////////////////////////////////////////////////////
H263plusVideoStreamFramer::H263plusVideoStreamFramer(
        UsageEnvironment &env,
        FramedSource *inputSource,
        Boolean createParser)
        : FramedFilter(env, inputSource),
          fFrameRate(0.0), // until we learn otherwise
          fPictureEndMarker(False) {
    // Use the current wallclock time as the base 'presentation time':
    gettimeofday(&fPresentationTimeBase, NULL);
    fParser = createParser ? new H263plusVideoStreamParser(this, inputSource) : NULL;
}

///////////////////////////////////////////////////////////////////////////////
H263plusVideoStreamFramer::~H263plusVideoStreamFramer() {
    delete fParser;
}


///////////////////////////////////////////////////////////////////////////////
void H263plusVideoStreamFramer::doGetNextFrame() {
    fParser->registerReadInterest(fTo, fMaxSize);
    continueReadProcessing();
}


///////////////////////////////////////////////////////////////////////////////
Boolean H263plusVideoStreamFramer::isH263plusVideoStreamFramer() const {
    return True;
}

///////////////////////////////////////////////////////////////////////////////
void H263plusVideoStreamFramer::continueReadProcessing(
        void *clientData,
        unsigned char * /*ptr*/, unsigned /*size*/,
        struct timeval /*presentationTime*/) {
    H263plusVideoStreamFramer *framer = (H263plusVideoStreamFramer *) clientData;
    framer->continueReadProcessing();
}

///////////////////////////////////////////////////////////////////////////////
void H263plusVideoStreamFramer::continueReadProcessing() {
    unsigned acquiredFrameSize;

    u_int64_t frameDuration;  // in ms

    acquiredFrameSize = fParser->parse(frameDuration);
// Calculate some average bitrate information (to be adapted)
//	avgBitrate = (totalBytes * 8 * H263_TIMESCALE) / totalDuration;

    if (acquiredFrameSize > 0) {
        // We were able to acquire a frame from the input.
        // It has already been copied to the reader's space.
        fFrameSize = acquiredFrameSize;
//    fNumTruncatedBytes = fParser->numTruncatedBytes(); // not needed so far

        fFrameRate = frameDuration == 0 ? 0.0 : 1000. / (long) frameDuration;

        // Compute "fPresentationTime"
        if (acquiredFrameSize == 5) // first frame
            fPresentationTime = fPresentationTimeBase;
        else
            fPresentationTime.tv_usec += (long) frameDuration * 1000;

        while (fPresentationTime.tv_usec >= 1000000) {
            fPresentationTime.tv_usec -= 1000000;
            ++fPresentationTime.tv_sec;
        }

        // Compute "fDurationInMicroseconds"
        fDurationInMicroseconds = (unsigned int) frameDuration * 1000;;

        // Call our own 'after getting' function.  Because we're not a 'leaf'
        // source, we can call this directly, without risking infinite recursion.
        afterGetting(this);
    } else {
        // We were unable to parse a complete frame from the input, because:
        // - we had to read more data from the source stream, or
        // - the source stream has ended.
    }
}
